import os
import logging
from io import BytesIO
from typing import Optional, Tuple
from PIL import Image, ImageOps
import hashlib

from app.utils import clean_cache_filename, ensure_directory_exists

logger = logging.getLogger(__name__)

class ImageProcessor:
    """图片处理服务"""
    
    def __init__(self, app=None):
        self.app = app
        self.cache_dir = ""
        self.thumbnail_dir = ""
        self.image_quality = 85
        self.thumbnail_size = (300, 400)
        self.max_image_size = (1920, 1080)  # 最大图片尺寸
        
        if app:
            self.init_app(app)
    
    def init_app(self, app):
        """初始化应用"""
        self.app = app
        self.cache_dir = os.path.join(app.config.get('CACHE_DIR', ''), 'images')
        self.thumbnail_dir = os.path.join(app.config.get('CACHE_DIR', ''), 'thumbnails')
        self.image_quality = app.config.get('IMAGE_QUALITY', 85)
        self.thumbnail_size = tuple(app.config.get('THUMBNAIL_SIZE', (300, 400)))
        
        # 确保缓存目录存在
        ensure_directory_exists(self.cache_dir)
        ensure_directory_exists(self.thumbnail_dir)
    
    def get_image_info(self, image_path: str) -> Optional[dict]:
        """获取图片信息"""
        try:
            if not os.path.exists(image_path):
                return None
            
            with Image.open(image_path) as img:
                return {
                    'width': img.width,
                    'height': img.height,
                    'format': img.format,
                    'mode': img.mode,
                    'file_size': os.path.getsize(image_path)
                }
        except Exception as e:
            logger.error(f"获取图片信息失败 {image_path}: {e}")
            return None
    
    def process_image(self, image_path: str, quality: Optional[int] = None, 
                     max_size: Optional[Tuple[int, int]] = None) -> Optional[str]:
        """
        处理图片并返回缓存路径
        
        Args:
            image_path: 原始图片路径
            quality: 压缩质量 (1-100)
            max_size: 最大尺寸 (width, height)
        
        Returns:
            处理后的图片缓存路径
        """
        try:
            if not os.path.exists(image_path):
                return None
            
            # 生成缓存文件名
            cache_filename = self._generate_cache_filename(
                image_path, quality or self.image_quality, max_size
            )
            cache_path = os.path.join(self.cache_dir, cache_filename)
            
            # 如果缓存文件已存在且较新，直接返回
            if os.path.exists(cache_path):
                if os.path.getmtime(cache_path) >= os.path.getmtime(image_path):
                    return cache_path
            
            # 处理图片
            with Image.open(image_path) as img:
                # 转换RGBA到RGB（如果需要保存为JPEG）
                if img.mode in ('RGBA', 'LA') or (img.mode == 'P' and 'transparency' in img.info):
                    background = Image.new('RGB', img.size, (255, 255, 255))
                    if img.mode == 'P':
                        img = img.convert('RGBA')
                    background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
                    img = background
                elif img.mode != 'RGB':
                    img = img.convert('RGB')
                
                # 调整大小
                target_size = max_size or self.max_image_size
                if img.width > target_size[0] or img.height > target_size[1]:
                    img.thumbnail(target_size, Image.Resampling.LANCZOS)
                
                # 保存处理后的图片
                img.save(
                    cache_path, 
                    'JPEG', 
                    quality=quality or self.image_quality,
                    optimize=True,
                    progressive=True
                )
                
                logger.debug(f"图片处理完成: {image_path} -> {cache_path}")
                return cache_path
                
        except Exception as e:
            logger.error(f"图片处理失败 {image_path}: {e}")
            return None
    
    def create_thumbnail(self, image_path: str, size: Optional[Tuple[int, int]] = None) -> Optional[str]:
        """
        创建缩略图
        
        Args:
            image_path: 原始图片路径
            size: 缩略图尺寸
        
        Returns:
            缩略图缓存路径
        """
        try:
            if not os.path.exists(image_path):
                return None
            
            thumbnail_size = size or self.thumbnail_size
            
            # 生成缩略图文件名
            thumbnail_filename = self._generate_thumbnail_filename(image_path, thumbnail_size)
            thumbnail_path = os.path.join(self.thumbnail_dir, thumbnail_filename)
            
            # 如果缩略图已存在且较新，直接返回
            if os.path.exists(thumbnail_path):
                if os.path.getmtime(thumbnail_path) >= os.path.getmtime(image_path):
                    return thumbnail_path
            
            # 创建缩略图
            with Image.open(image_path) as img:
                # 使用ImageOps.fit来创建居中裁剪的缩略图
                thumbnail = ImageOps.fit(
                    img, 
                    thumbnail_size, 
                    Image.Resampling.LANCZOS,
                    centering=(0.5, 0.5)
                )
                
                # 转换为RGB（如果需要）
                if thumbnail.mode in ('RGBA', 'LA') or (thumbnail.mode == 'P' and 'transparency' in thumbnail.info):
                    background = Image.new('RGB', thumbnail.size, (255, 255, 255))
                    if thumbnail.mode == 'P':
                        thumbnail = thumbnail.convert('RGBA')
                    background.paste(thumbnail, mask=thumbnail.split()[-1] if thumbnail.mode == 'RGBA' else None)
                    thumbnail = background
                elif thumbnail.mode != 'RGB':
                    thumbnail = thumbnail.convert('RGB')
                
                # 保存缩略图
                thumbnail.save(
                    thumbnail_path,
                    'JPEG',
                    quality=80,
                    optimize=True
                )
                
                logger.debug(f"缩略图创建完成: {image_path} -> {thumbnail_path}")
                return thumbnail_path
                
        except Exception as e:
            logger.error(f"缩略图创建失败 {image_path}: {e}")
            return None
    
    def get_processed_image_path(self, image_path: str, quality: Optional[int] = None,
                                max_size: Optional[Tuple[int, int]] = None) -> str:
        """获取处理后的图片路径，如果不存在则创建"""
        processed_path = self.process_image(image_path, quality, max_size)
        return processed_path or image_path
    
    def get_thumbnail_path(self, image_path: str, size: Optional[Tuple[int, int]] = None) -> str:
        """获取缩略图路径，如果不存在则创建"""
        thumbnail_path = self.create_thumbnail(image_path, size)
        return thumbnail_path or image_path
    
    def _generate_cache_filename(self, image_path: str, quality: int, 
                                max_size: Optional[Tuple[int, int]]) -> str:
        """生成缓存文件名"""
        # 创建唯一标识符
        size_str = f"{max_size[0]}x{max_size[1]}" if max_size else "original"
        identifier = f"{image_path}_{quality}_{size_str}"
        hash_str = hashlib.md5(identifier.encode()).hexdigest()
        
        # 获取原始文件名（不含扩展名）
        original_name = os.path.splitext(os.path.basename(image_path))[0]
        safe_name = clean_cache_filename(original_name)
        
        return f"{safe_name}_{hash_str}.jpg"
    
    def _generate_thumbnail_filename(self, image_path: str, size: Tuple[int, int]) -> str:
        """生成缩略图文件名"""
        # 创建唯一标识符
        identifier = f"{image_path}_thumb_{size[0]}x{size[1]}"
        hash_str = hashlib.md5(identifier.encode()).hexdigest()
        
        # 获取原始文件名（不含扩展名）
        original_name = os.path.splitext(os.path.basename(image_path))[0]
        safe_name = clean_cache_filename(original_name)
        
        return f"thumb_{safe_name}_{hash_str}.jpg"
    
    def clear_cache(self, cache_type: str = 'all') -> bool:
        """清理缓存"""
        try:
            if cache_type in ('all', 'images'):
                self._clear_directory(self.cache_dir)
                logger.info("图片缓存已清理")
            
            if cache_type in ('all', 'thumbnails'):
                self._clear_directory(self.thumbnail_dir)
                logger.info("缩略图缓存已清理")
            
            return True
            
        except Exception as e:
            logger.error(f"清理缓存失败: {e}")
            return False
    
    def _clear_directory(self, directory: str):
        """清理目录中的所有文件"""
        if not os.path.exists(directory):
            return
        
        for filename in os.listdir(directory):
            file_path = os.path.join(directory, filename)
            try:
                if os.path.isfile(file_path):
                    os.unlink(file_path)
            except OSError as e:
                logger.warning(f"删除缓存文件失败 {file_path}: {e}")
    
    def get_cache_stats(self) -> dict:
        """获取缓存统计信息"""
        def get_dir_stats(directory):
            if not os.path.exists(directory):
                return {'count': 0, 'size': 0}
            
            count = 0
            size = 0
            
            try:
                for filename in os.listdir(directory):
                    file_path = os.path.join(directory, filename)
                    if os.path.isfile(file_path):
                        count += 1
                        size += os.path.getsize(file_path)
            except OSError:
                pass
            
            return {'count': count, 'size': size}
        
        image_stats = get_dir_stats(self.cache_dir)
        thumbnail_stats = get_dir_stats(self.thumbnail_dir)
        
        return {
            'images': image_stats,
            'thumbnails': thumbnail_stats,
            'total_files': image_stats['count'] + thumbnail_stats['count'],
            'total_size': image_stats['size'] + thumbnail_stats['size']
        }
    
    def convert_to_webp(self, image_path: str, quality: int = 80) -> Optional[str]:
        """将图片转换为WebP格式"""
        try:
            if not os.path.exists(image_path):
                return None
            
            # 生成WebP文件名
            webp_filename = self._generate_webp_filename(image_path, quality)
            webp_path = os.path.join(self.cache_dir, webp_filename)
            
            # 如果WebP文件已存在且较新，直接返回
            if os.path.exists(webp_path):
                if os.path.getmtime(webp_path) >= os.path.getmtime(image_path):
                    return webp_path
            
            # 转换为WebP
            with Image.open(image_path) as img:
                img.save(
                    webp_path,
                    'WebP',
                    quality=quality,
                    optimize=True
                )
                
                logger.debug(f"WebP转换完成: {image_path} -> {webp_path}")
                return webp_path
                
        except Exception as e:
            logger.error(f"WebP转换失败 {image_path}: {e}")
            return None
    
    def _generate_webp_filename(self, image_path: str, quality: int) -> str:
        """生成WebP文件名"""
        identifier = f"{image_path}_webp_{quality}"
        hash_str = hashlib.md5(identifier.encode()).hexdigest()
        
        original_name = os.path.splitext(os.path.basename(image_path))[0]
        safe_name = clean_cache_filename(original_name)
        
        return f"{safe_name}_{hash_str}.webp"

# 全局实例
image_processor = ImageProcessor()